package com.shitou.shitouorder.utils;

import com.shitou.shitoucommons.exception.RRException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 功能描述: 分布式锁
 * @author ShiTou
 * the class {RedisTemplateUtils} create time is
 * @date 2022年04月24日9:52
 */
@Component
@Slf4j
@SuppressWarnings("all")
public class RedisTemplateUtil {


    private static final String LOCK_PREFIX = "RedisLock";  // 锁名称
    private static final int LOCK_EXPIRE = 2000;  // 锁失效时间，单位毫秒
    private static final int COUNT = 300;  // 轮询次数
    private static final int INTERVAL = 5; // 每次轮询的间隔时间,单位毫秒

    @Autowired
    @Qualifier("RedisTemplate")
    private RedisTemplate redisTemplate;

    /**
     * 功能描述: 对key进行加锁操作
     * @param key 锁名称
     * @return
     */
    public Boolean setLock(String key, int lockExpire){
        // 如果当前key为nil，那么赋值 返回true
        // 不为nil，那么不做操作，返回false
        return redisTemplate.opsForValue().setIfAbsent(key, LOCK_PREFIX, lockExpire, TimeUnit.MILLISECONDS);
    }
    public Boolean setLock(String key){
        return setLock(key,LOCK_EXPIRE);
    }


    /**
     * 功能描述: 释放锁
     * @param key 锁名称
     * @return
     */
    public Boolean deleteLock(String key){
        return redisTemplate.delete(key);
    }


    /**
     * 功能描述: 1,采用轮询方式加锁
     * 2, 获得锁
     * @param key 锁名称
     * @return
     */
    public Boolean tryCasLock(String key,int count){
        while ( count > 0 ){
            count --;
            if ( setLock(key) ) {   // 由于之前设置了锁，那么当第一次访问的时候,它直接返回false,线程进行轮询等待
                return true;   // 取得锁,重新设置
            }else {
                try{
                    Thread.sleep(INTERVAL);
                }catch (InterruptedException e){
                    e.printStackTrace();
                    throw new RRException("服务繁忙，请重试");
                }
            }
        }
        // 如果没有取得锁，那么返回false
        return false;
    }
    public Boolean tryCasLock(String key){
        return tryCasLock(key,COUNT);
    }
}
